package JET.geom;

import java.util.ArrayList;

/**
 *
 * @author 057Ry
 */
public final class Sec2d
{
    private final Vec2d v1,v2;

    public Sec2d(Vec2d v1,Vec2d v2)
    {
        this.v1 = new Vec2d( v1 );
        this.v2 = new Vec2d( v2 );
    }

    public Vec2d getV1() {
        return v1;
    }
    public Vec2d getV2() {
        return v2;
    }
    public double getVx()
    {
        return v2.getX()-v1.getX();
    }
    public double getVy()
    {
        return v2.getY()-v1.getY();
    }

    public Vec2d getVector()
    {
        return new Vec2d(getVx(), getVy());
    }
    public double getAngleX()
    {
        Vec2d vec = new Vec2d( getVx(), getVy() );
        return vec.getAngleX();
    }
    public double getAngleY()
    {
        Vec2d vec = new Vec2d( getVx(), getVy() );
        return vec.getAngleY();
    }
    public double getLength()
    {
        return getVector().getMagnitude();
    }
    public double getLengthSquared()
    {
        return getVector().getMagnitudeSquared();
    }

    public Sec2dIntersectionInfo getIntersectionInfo(Sec2d sec)
    {
        // Wyznacznik dwoch wektorow
        double detPlp2 = getVx() * sec.getVy() - this.getVy() * sec.getVx();
        
        // Test czy odcinki sa rownolegle
        if( Math.abs(detPlp2) <= 0.0000001 )
            return null;

        double t1 = (sec.getVx() * (this.v1.getY() - sec.getV1().getY()) - sec.getVy() * (this.v1.getX() - sec.getV1().getX())) / detPlp2;
        double t2 = (this.getVx() * (this.v1.getY() - sec.getV1().getY()) - this.getVy() * (this.v1.getX() - sec.getV1().getX())) / detPlp2;

        if ( t1>=0 && t1<=1 && t2>=0 && t2<=1)
        {
            Vec2d intrsVec = new Vec2d( v1.getX()+getVx()*t1, v1.getY()+getVy()*t1 );
            return new Sec2dIntersectionInfo(intrsVec, t1);
        }

        return null;
    }
    public ArrayList<Sec2dIntersectionInfo> getIntersectionInfo(Circle circle)
    {
        double Vx = getVx();
        double Vy = getVy();
        double Psx = getV1().getX();
        double Psy = getV1().getY();
        double a = circle.center.getX();
        double b = circle.center.getY();
        double r = circle.radius;
        
        //System.out.println("GetIntersectionInfo() --> Vx="+Vx+" Vy="+Vy+" Psx="+Psx+" Psy="+Psy+" a="+a+" b="+b+" r="+r);
        double A = Vx*Vx + Vy*Vy;
        double B = 2*(Psx*Vx + Psy*Vy - a*Vx - b*Vy);
        double C = Psx*Psx + Psy*Psy - 2*(a*Psx + b*Psy) + a*a + b*b - r*r;
        
        double delta = B*B - 4*A*C;
        //System.out.println("                          A="+A+" B="+B+" C="+C+" delta="+delta);
        
        //System.out.println("              
        ArrayList<Sec2dIntersectionInfo> list = new ArrayList<Sec2dIntersectionInfo>(2);
        
        if ( delta == 0 ) // prosta jest styczny do okregu
        {
            double t = -1*B/(2*A);
            if ( t>=0 && t<=1 ) // jezeli punkt styku nalezy do odcinka
            {
                Vec2d tmp = new Vec2d(Vx*t, Vy*t);
                Vec2d result = new Vec2d( getV1() );
                result.add(tmp);
                list.add( new Sec2dIntersectionInfo(result, t) );
            }
        }
        else if ( delta > 0 ) // prosta przecina okrag w 2 miejscach
        {
            double t1 = ( -1*B+Math.sqrt(delta) )/( 2*A );
            double t2 = ( -1*B-Math.sqrt(delta) )/( 2*A );
            Vec2d result1=null, result2=null;
            if ( t1>=0 && t1<=1 ) // jezeli 1 punkt przeciecia nalezy do odcinka
            {
                Vec2d tmp = new Vec2d(Vx*t1, Vy*t1);
                
                result1 = new Vec2d( getV1() );
                result1.add(tmp);
                list.add( new Sec2dIntersectionInfo(result1, t1) );
            }
            if ( t2>=0 && t2<=1 ) // jezeli 2 punkt przeciecia nalezy do odcinka
            {
                Vec2d tmp = new Vec2d(Vx*t2, Vy*t2);
                
                result2 = new Vec2d( getV1() );
                result2.add(tmp);
                list.add( new Sec2dIntersectionInfo(result2, t2) );
            }
        }
        else if ( delta < 0 ) // prosta nie ma punktow wspolnych z okregiem
        {
        }
        return list;
    }

    public double getDistanceTo(Vec2d vec)
    {
        Vec2d normal = getVector().getPerp().getNormalized();
        Vec2d v1ToVec = vec.getSubbed(v1);
        
        return Math.abs( normal.dot(v1ToVec) );
    }

    /**
     * Returns true if given vector projected on line of this sector, lies on this sector.
     * @param vec tested vector
     * @return boolean value :]
     */
    public boolean isWithinBounds(Vec2d vec)
    {
        Vec2d v1ToVec = vec.getSubbed(v1);

        double dot = getVector().getNormalized().dot(v1ToVec);
        return dot>=0 && dot*dot<=getLengthSquared();
    }
    public String toString()
    {
        return "sec2d[ ("+v1.getX()+", "+v1.getY()+") ("+v2.getX()+", "+v2.getY()+") ]";
    }
}
